import { type Bundle } from "typescript";

const CALLSTACK = Symbol("__callstack__");

// 协程调度器
class CoroutineScheduler {
  /**
   * @type {Generator<Promise<void> | void, void, unknown>[]}
   */
  declare coroutines: Generator<Promise<void> | void, void, unknown>[];

  declare running: boolean;

  constructor() {
    this.coroutines = [];
    this.running = false;
  }

  addCoroutine<
    T extends (name: string, max: number) => Generator<void, void, unknown>,
  >(genFunc: T, name: string, max: number): void;
  addCoroutine<T extends void>(
    genFunc: () => Generator<T, void, unknown>,
    ...args: []
  ): void;
  addCoroutine<T extends Promise<void>>(
    genFunc: () => Generator<T, void, unknown>,
    ...args: []
  ): void;
  addCoroutine(
    genFunc: (
      name?: string,
      max?: number,
    ) => Generator<void | Promise<void>, void, unknown>,
    ...args: [string, number] | []
  ) {
    /**
     *  @type Generator<Promise<void> | void, void, unknown>
     */
    const coroutine: Generator<Promise<void> | void, void, unknown> =
      Array.isArray(args) && args.length === 2 ? genFunc(...args) : genFunc();
    this.coroutines.push(coroutine);
    if (!this.running) {
      this.run();
    }
  }

  // 清空协程队列
  async run() {
    this.running = true;
    while (this.coroutines.length > 0) {
      const coroutine = this.coroutines.shift();
      // none out
      if (!coroutine) {
        break;
      }
      const { value, done } = coroutine.next();

      if (done) {
        this.log("Coroutine completed");
      } else {
        await (value instanceof Promise
          ? value
          : new Promise((resolve) => {
              setTimeout(resolve, 100);
            }));
        this.coroutines.push(coroutine);
      }
    }
    this.running = false;
  }

  /**
   * @param {string} message
   */
  log(message: string) {
    console.log("[message]", message);
    // const output = document.getElementById("output");
    // if (!output) return
    // output.textContent += message + "\n";
    // output.scrollTop = output.scrollHeight;
  }
}

// 创建调度器实例
const scheduler = new CoroutineScheduler();

// 示例协程函数
/**
 * @param {string} name
 * @param {number} max
 * @returns {Generator<void, void, unknown>}
 */
function* counterCoroutine(
  name: string,
  max: number,
): Generator<void, void, unknown> {
  for (let i = 1; i <= max; i++) {
    scheduler.log(`${name}: ${i}`);
    yield; // 暂停执行，让出控制权
  }
  scheduler.log(`${name} finished!`);
}
/**
 * @returns {Generator<void, void, unknown>}
 */
function* dataProcessor(): Generator<void, void, unknown> {
  const data = [10, 20, 30, 40, 50];
  let sum = 0;

  for (const item of data) {
    scheduler.log(`Processing data: ${item}`);
    sum += item;
    yield;
  }

  scheduler.log(`Data processed. Total sum: ${sum}`);
}
/**
 * @returns {Generator<void, void, unknown>}
 */
function* nestedCoroutine() {
  scheduler.log("Starting nested coroutine");
  yield* counterCoroutine("Nested Counter", 3);
  scheduler.log("Nested coroutine completed");
}
/**
 * @returns {Generator<Promise<void>, void, unknown>}
 */
function* asyncSimulation(): Generator<Promise<void>, void, unknown> {
  scheduler.log("Starting async simulation...");
  yield new Promise((resolve) => {
    setTimeout(resolve, 300);
  });
  scheduler.log("Async step 1 completed");
  yield new Promise((resolve) => {
    setTimeout(resolve, 300);
  });
  scheduler.log("Async step 2 completed");
  scheduler.log("Async simulation finished");
}

// 启动所有协程
function startCoroutines() {
  scheduler.addCoroutine(counterCoroutine, "Coroutine A", 5);
  scheduler.addCoroutine(counterCoroutine, "Coroutine B", 3);
  scheduler.addCoroutine(dataProcessor);
  scheduler.addCoroutine(nestedCoroutine);
  scheduler.addCoroutine(asyncSimulation);
}

console.time("coroutine");
startCoroutines();
process.on("exit", () => {
  console.timeEnd("coroutine");
});
